package database

import (
	"database/sql"
	"fmt"
	"log/slog"

	_ "github.com/go-sql-driver/mysql"
	_ "github.com/sijms/go-ora/v2"
)

type DBClient struct {
	name string
	db   *sql.DB
}

func NewDBClient(driver, source string) (*DBClient, error) {
	conn, err := sql.Open(driver, source)
	if err != nil {
		slog.Error(fmt.Sprintf("Can't open the database driver: %s", err))
		return nil, err
	}
	return &DBClient{name: driver, db: conn}, nil
}

func (o *DBClient) Close() error {
	err := o.db.Close()
	if err != nil {
		slog.Error(fmt.Sprintf("Can't close connection: %s", err))
		return err
	}
	return nil
}

// RetrieveMap SQL查询结果输出为Map
func (o *DBClient) RetrieveMap(sSql string) ([]map[string]interface{}, error) {

	// 准备查询语句
	stmt, err := o.db.Prepare(sSql)
	if err != nil {
		slog.Error(fmt.Sprintf("SQL prepare error: %s", err))
		return nil, err
	}
	defer stmt.Close()

	// 查询
	rows, err := stmt.Query()
	if err != nil {
		slog.Error(fmt.Sprintf("SQL query error: %s", err))
		return nil, err
	}
	defer rows.Close()

	// 数据列
	columns, err := rows.Columns()
	if err != nil {
		slog.Error(fmt.Sprintf("Get result column error: %s", err))
		return nil, err
	}

	// 列的个数
	count := len(columns)

	// 返回值 Map切片
	mData := make([]map[string]interface{}, 0)
	// 一条数据的各列的值（需要指定长度为列的个数，以便获取地址）
	values := make([]interface{}, count)
	// 一条数据的各列的值的地址
	valPointers := make([]interface{}, count)
	for rows.Next() {

		// 获取各列的值的地址
		for i := 0; i < count; i++ {
			valPointers[i] = &values[i]
		}

		// 获取各列的值，放到对应的地址中
		rows.Scan(valPointers...)

		// 一条数据的Map (列名和值的键值对)
		entry := make(map[string]interface{})

		// Map 赋值
		for i, col := range columns {
			var v interface{}

			// 值复制给val(所以Scan时指定的地址可重复使用)
			val := values[i]
			b, ok := val.([]byte)
			if ok {
				// 字符切片转为字符串
				v = string(b)
			} else {
				v = val
			}
			entry[col] = v
		}

		mData = append(mData, entry)
	}

	return mData, nil
}
